﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Globalization;

namespace RushTracker.Web
{
    public class TrackerAnnounceRequest
    {
        private static readonly string[] REQUIRED_PARAMETERS = new string[] { "info_hash", "peer_id", "port", "downloaded", "uploaded", "left" };

        private Dictionary<string, string> _queryParameters = new Dictionary<string, string>();

        public TrackerAnnounceRequest(HttpRequest request)
        {
            foreach (string p in REQUIRED_PARAMETERS)
            {
                if (String.IsNullOrEmpty(request.QueryString[p]))
                {
                    throw new AnnounceException(String.Format("Missing key '{0}'", p));
                }
            }

            string query = request.Url.Query;

            if (query.StartsWith("?"))
            {
                query = query.Substring(1);
            }

            string[] keyValuePairs = query.Split('&');

            foreach (string pair in keyValuePairs)
            {
                int firstEqualSign = pair.IndexOf("=");

                string pairKey = pair.Substring(0, firstEqualSign);
                string pairValue = pair.Substring(firstEqualSign + 1);

                this._queryParameters.Add(pairKey, pairValue);
            }

            // assign values
            string tempHash = this._queryParameters["info_hash"];
            PeerId = this._queryParameters["peer_id"];
            Port = Convert.ToInt32(this._queryParameters["port"]);
            Downloaded = Convert.ToInt64(this._queryParameters["downloaded"]);
            Uploaded = Convert.ToInt64(this._queryParameters["uploaded"]);
            Left = Convert.ToInt64(this._queryParameters["left"]);
            RequestedPeerCount = 0;
            IPAddress = request.UserHostAddress;

            if (this._queryParameters.ContainsKey("numwant"))
                RequestedPeerCount = Convert.ToInt32(this._queryParameters["numwant"]);

            if (Port == 0 || Port > 0xffff)
                throw new AnnounceException("Invalid port");

            if (this._queryParameters.ContainsKey("event"))
            {
                switch (this._queryParameters["event"])
                {
                    case "started":
                        Event = AnnounceRequestEvent.Started;
                        break;

                    case "stopped":
                        Event = AnnounceRequestEvent.Stopped;
                        break;

                    case "completed":
                        Event = AnnounceRequestEvent.Completed;
                        break;

                    default:
                        Event = AnnounceRequestEvent.Regular;
                        break;
                }
            }
            else
            {
                Event = AnnounceRequestEvent.Regular;
            }

            var ms = new MemoryStream();
            for (var i = 0; i < tempHash.Length; i++)
            {
                if (tempHash[i] == '%')
                {
                    ms.WriteByte(byte.Parse(tempHash.Substring(i + 1, 2), NumberStyles.AllowHexSpecifier));
                    i += 2;
                }
                else if (tempHash[i] < 128)
                {
                    ms.WriteByte((byte)tempHash[i]);
                }
            }

            InfoHash = BitConverter.ToString(ms.ToArray()).Replace("-", "");
        }

        public string InfoHash { get; set; }

        public string PeerId { get; set; }

        public string IPAddress { get; set; }

        public AnnounceRequestEvent Event { get; set; }

        public int Port { get; set; }

        public long Downloaded { get; set; }

        public long Uploaded { get; set; }

        public long Left { get; set; }

        public int RequestedPeerCount { get; set; }
    }
}
